package com.bupt.ilink.service.studyaboutTeacherCourse;
import com.google.common.util.concurrent.RateLimiter; // 引入Guava的RateLimiter

import com.bupt.ilink.controller.LearningPlaza.File.FileHandleController;
import com.bupt.ilink.entity.Studyspace.CourseSource;
import com.bupt.ilink.entity.Studyspace.StudyCourseFile;
import com.bupt.ilink.entity.Studyspace.StudyFileSource;
import com.bupt.ilink.mapper.CourseSourceMapper;
import com.bupt.ilink.mapper.StudyCourseFileMapper;
import com.bupt.ilink.mapper.StudyFileSourceMapper;
import com.bupt.ilink.service.OssService;
import com.bupt.ilink.service.StudyaboutTeacherService;
import com.bupt.ilink.service.bailian.FileService;
import com.bupt.ilink.utils.R;
import com.bupt.ilink.utils.SnowflakeIdGenerator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import org.springframework.core.io.ByteArrayResource;
import java.net.URL;
//import org.springframework.web.multipart.commons.CommonsMultipartFile;


import java.util.concurrent.ThreadPoolExecutor;

@Slf4j
@Service
public class FileSourceHandleThreadService {
    //并发队列处理文件上传和加工
    private final ThreadPoolExecutor fileUploadTaskExecutor;
    private final ThreadPoolExecutor fileHandleTaskExecutor;

    //处理音视频的线程池
    private final ThreadPoolExecutor videoHandleTaskExecutor;

    //限流控制
    // 每分钟限制 上传任务30 次请求，可以根据需要调整速率
    private final RateLimiter UploadRateLimiter = RateLimiter.create(30.0 / 60); // 每秒最多允许 0.5 次请求，相当于每分钟 30 次请求
    private final RateLimiter HandleRateLimiter = RateLimiter.create(10.0 / 60);//加工的先限制十个


    @Autowired
    private OssService ossService;

    @Autowired
    private FileService fileService;

    @Autowired
    private StudyaboutTeacherService studyaboutTeacherService;

    @Autowired
    private CourseSourceMapper courseSourceMapper;

    @Autowired
    private StudyFileSourceMapper studyFileSourceMapper;

    @Autowired
    private StudyCourseFileMapper studyCourseFileMapper;

    @Autowired
    private FileHandleController fileHandleController;

    @Autowired
    public FileSourceHandleThreadService(
            ThreadPoolExecutor fileUploadTaskExecutor,
            ThreadPoolExecutor fileHandleTaskExecutor,
            ThreadPoolExecutor videoHandleTaskExecutor
    ) {
        this.fileUploadTaskExecutor = fileUploadTaskExecutor;
        this.fileHandleTaskExecutor = fileHandleTaskExecutor;
        this.videoHandleTaskExecutor = videoHandleTaskExecutor;
    }

    public static File convertMultipartFileToFile(MultipartFile multipartFile,String directoryPath,String newFilename) throws IOException {

        // 创建文件目录
        File directory = new File(directoryPath);
        if (!directory.exists()) {
            // 如果目录不存在则创建目录
            boolean dirsCreated = directory.mkdirs();
            if (!dirsCreated) {
                throw new IOException("无法创建目录: " + directoryPath);
            }
        }
        String fileName;
        // 创建本地文件名，可以使用上传的文件名，也可以使用UUID作为文件名
        if (newFilename == null || newFilename.isEmpty()) {
            fileName = multipartFile.getOriginalFilename();
        }else {
            fileName = newFilename;
        }
         // 获取上传文件的原始名称
        File file = new File(directoryPath + File.separator + fileName);  // 构建完整的文件路径

        // 将 MultipartFile 转存为 File
        multipartFile.transferTo(file);

        return file;  // 返回存储后的文件对象
    }

    //1.上传文档至OSS和百炼及转写生成加工
    public R uploadFileTask(MultipartFile file, Long courseFileId, Long courseId) {
        try {
            // 获取原始文件名
            String originalFilename = file.getOriginalFilename();

            // 获取文件扩展名
            String fileExtension = "";
            if (originalFilename != null && originalFilename.contains(".")) {
                fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));
            } else {
                return R.failure("文件解析扩展名出现错误：" + originalFilename);
            }

            // 生成新文件名，使用雪花算法生成的ID
            SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(1, 1);
            Long id = idGenerator.nextId();
            String newFilename = id + fileExtension;

            // 获取对应的文件路径，用于关联和存储上传
            StudyCourseFile studyCourseFile = studyCourseFileMapper.selectById(courseFileId);
            if (studyCourseFile == null) {
                return R.failure("文件夹ID无效");
            }
            String filePath = studyCourseFile.getFilePath();

            // 构建并保存资源信息到数据库
            StudyFileSource courseSource = new StudyFileSource();
            courseSource.setFilesourceId(id);
            courseSource.setFileName(file.getOriginalFilename());
            courseSource.setFileId(courseFileId);
            courseSource.setCourseId(courseId);
            courseSource.setFilesourcePath(filePath + newFilename);
            boolean insertSuccess = studyFileSourceMapper.insert(courseSource)>0;
            //新存储一个顺序表
            
            if (insertSuccess){
                // 更新 Redis 状态为 "待处理"
//            redisTemplate.opsForHash().put("fileUploadStatus", courseSource.getFilesourceId().toString(), "待处理");
                //将文件存储在本地
                //TODO:将文件存储在本地 改路径到配置文件
                File savedFile = convertMultipartFileToFile(file, "D:\\code\\代码\\java\\ilink\\src\\main\\resources\\data\\fileSource\\", newFilename);//+filePath
                // 将上传任务提交到线程池执行
                fileUploadTaskExecutor.execute(() -> {
                    // 等待获取速率限制许可
                    UploadRateLimiter.acquire();
                    processFileUpload(savedFile, filePath, newFilename, courseSource);
                } );

                return R.ok("文件已加入队列中处理，稍后处理: " + file.getOriginalFilename());
            }else {
                log.error("文件加入mysql时失败: " + file.getOriginalFilename());
                return R.failure("文件加入mysql时失败: " + file.getOriginalFilename());
            }
        } catch (Exception e) {
            //直接更改mysql中文件状态
//            StudyFileSource fileSource = studyFileSourceMapper.selectById(fileSourceId);
            return R.failure("文件上传失败: " + file.getOriginalFilename(),e.getMessage());
        }
    }
    // 处理文件上传MultipartFile file
    private void processFileUpload(File file, String filePath, String newFilename, StudyFileSource courseSource) {
        try {
            boolean uploadSuccess = ossService.uploadFile(file, filePath, newFilename);
            if (uploadSuccess) {
                courseSource.setOssWriteStatus(true);
                boolean updateSuccess =studyFileSourceMapper.updateById(courseSource)>0;
                if (!updateSuccess) {
                    log.error("课程:"+courseSource.getCourseId()+"中的文件:"+courseSource.getFilesourceId()+"上传成功，但更新数据库失败: " + file.getName());
                    //需要进行回退处理删除
                    boolean deleted= ossService.deleteFile(newFilename,filePath);
                    if (!deleted) {
                        log.error("课程:"+courseSource.getCourseId()+"中的文件:"+courseSource.getFilesourceId()+"上传成功，但更新数据库失败，但OSS删除失败，请手动删除: " + file.getName());
                    }else {
                        log.info("课程:" + courseSource.getCourseId() + "中的文件:" + courseSource.getFilesourceId() + "上传成功，但更新数据库失败，已进行OSS删除回退处理: " + file.getName());
                    }
                    //更新状态，即当前状态为加工失败
                    courseSource.setHandleCompleteStatus(true);
                    updateSuccess =studyFileSourceMapper.updateById(courseSource)>0;
                    if (!updateSuccess) {
                        log.error("课程:"+courseSource.getCourseId()+"中的文件:"+courseSource.getFilesourceId()+"更新数据库失败导致的加工失败，且状态未能更新: " + file.getName());
                    }
                }else {
                    log.info("课程:"+courseSource.getCourseId()+"中的文件:"+courseSource.getFilesourceId()+"上传成功: " + file.getName());
                    //将上传百炼和加工的任务提交到线程池执行，但前提是确保上传成功
                    fileHandleTaskExecutor.execute(() -> {
                        // 等待获取速率限制许可
                        HandleRateLimiter.acquire();
                        processFileHandle(file,courseSource,filePath, newFilename,courseSource.getCourseId());
                    });
                    log.info("课程:"+courseSource.getCourseId()+"中的文件:"+courseSource.getFilesourceId()+"上传成功，已提交处理任务: " + file.getName());
                }

                // 更新 Redis 状态为 "上传成功"
//                redisTemplate.opsForHash().put("fileUploadStatus", courseSource.getFilesourceId().toString(), "上传成功");
            } else {
                log.error("课程:"+courseSource.getCourseId()+"中的文件:"+courseSource.getFilesourceId()+"上传失败: " + file.getName());
                //更新状态，即当前状态为加工失败
                courseSource.setHandleCompleteStatus(true);
                boolean updateSuccess =studyFileSourceMapper.updateById(courseSource)>0;
                if (!updateSuccess) {
                    log.error("课程:"+courseSource.getCourseId()+"中的文件:"+courseSource.getFilesourceId()+"上传失败，且加工状态更新数据库失败: " + file.getName());
                }
                // 更新 Redis 状态为 "上传失败"
//                redisTemplate.opsForHash().put("fileUploadStatus", courseSource.getFilesourceId().toString(), "上传失败");
            }
        } catch (Exception e) {
            // 更新 Redis 状态为 "上传失败"
//            redisTemplate.opsForHash().put("fileUploadStatus", courseSource.getFilesourceId().toString(), "上传失败");
            log.error("课程:"+courseSource.getCourseId()+"中的文件:"+courseSource.getFilesourceId()+"上传中出现异常: " + file.getName(), e);
            //更新状态，即当前状态为加工失败
            courseSource.setHandleCompleteStatus(true);
            boolean updateSuccess =studyFileSourceMapper.updateById(courseSource)>0;
            if (!updateSuccess) {
                log.error("课程:"+courseSource.getCourseId()+"中的文件:"+courseSource.getFilesourceId()+"上传失败，且加工状态更新数据库失败: " + file.getName());
            }
        }
    }



    //RAG加工和百炼上传加工MultipartFile file,
    private void processFileHandle(File file,StudyFileSource fileSource, String filePath, String newFilename,Long courseId) {
        try {
            String fileUrl = ossService.getFileUrl(fileSource.getFilesourcePath());
            if (fileUrl == null) {
                log.error("课程:" + courseId + "中的文件URL未找到: " + fileSource.getFileName());
            }
            //RAG上传加工
//            String tempFilePath = "tempFile_rag" + fileSource.getFilesourceId() + ".tmp";
//            MultipartFile file= downloadFile1(fileUrl, tempFilePath);
//            File file = new File(tempFilePath);
//            MultipartFile file = getMultipartFileFromUrl(fileUrl,tempFilePath);
            R response = fileService.uploadFile(file, filePath, newFilename);
            if (response == null || response.getCode() == 0) {
                if (response != null) {
                    fileSource.setHandleCompleteStatus(true);
                    studyFileSourceMapper.updateById(fileSource);
                    log.error("课程:" + courseId + "中的RAG文件:"+fileSource.getFilesourceId()+"上传失败: " + fileSource.getFileName() + " " + response.getMsg());

                } else {
                    fileSource.setHandleCompleteStatus(true);
                    studyFileSourceMapper.updateById(fileSource);
                    log.error("课程:" + courseId + "中的RAG文件:"+fileSource.getFilesourceId()+"上传失败: " + fileSource.getFileName());
                }
            } else {
                fileSource.setRagCompleteStatus(true);
                studyFileSourceMapper.updateById(fileSource);

            }
            //调用听悟api
            response = fileHandleController.uploadFileFromUrl(fileUrl, fileSource.getFilesourceId());
            if (response == null || response.getCode() == 0) {
                if (response != null) {
                    fileSource.setHandleCompleteStatus(true);
                    studyFileSourceMapper.updateById(fileSource);
                    log.error("课程:" + courseId + "中的文件:"+fileSource.getFilesourceId()+"加工失败: " + fileSource.getFileName() + " " + response.getMsg());
                } else {
                    fileSource.setHandleCompleteStatus(true);
                    studyFileSourceMapper.updateById(fileSource);
                    log.error("课程:" + courseId + "中的文件:"+fileSource.getFilesourceId()+"加工失败: " + fileSource.getFileName());
                }
            } else {
                fileSource.setSmartTextStatus(true);
                fileSource.setHandleCompleteStatus(true);
                studyFileSourceMapper.updateById(fileSource);
//                return R.ok("文件加工转写成功: " +  fileSource.getFileName(),response);
                log.info("课程:" + courseId + "中的文件:"+fileSource.getFilesourceId()+"加工转写成功: " + fileSource.getFileName());
            }

        } catch (Exception e) {
            log.error("课程:" + courseId + "中的文件:"+fileSource.getFilesourceId()+"上传中出现异常: " , e);
            //更新状态，即当前状态为加工失败
            fileSource.setHandleCompleteStatus(true);
            boolean updateSuccess =studyFileSourceMapper.updateById(fileSource)>0;
            if (!updateSuccess) {
                log.error("课程:"+fileSource.getCourseId()+"中的文件:"+fileSource.getFilesourceId()+"上传失败，且加工状态更新数据库失败: " );
            }
        }
    }


    //2.上传音视频
    public R uploadSourceTask (MultipartFile file, Long courseFileId, String language,Boolean isTranslated,String speakerType,Long courseid) {
        try {
            // 获取原始文件名
            String originalFilename = file.getOriginalFilename();

            // 获取文件扩展名
            String fileExtension = "";
            if (originalFilename != null && originalFilename.contains(".")) {
                fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));
            }else {
                return R.failure("文件解析扩展名出现错误："+originalFilename);
            }
            // 生成新文件名，使用雪花算法生成的ID
            SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(1, 1);
            Long id = idGenerator.nextId();
            String newFilename = id+ fileExtension;
            // 获取对应的文件路径，用于关联和存储上传
            StudyCourseFile studyCourseFile = studyCourseFileMapper.selectById(courseFileId);
            if (studyCourseFile == null) {
                return R.failure("文件夹ID无效");
            }
            String filePath = studyCourseFile.getFilePath();
            CourseSource courseSource = new CourseSource();
            courseSource.setCourseSourceId(id);
            courseSource.setLanguage(language);
            courseSource.setIsTranslated(isTranslated);
            courseSource.setSpeakerType(speakerType);
            courseSource.setFileId(courseFileId);
            courseSource.setFileName(file.getOriginalFilename());
            courseSource.setCourseId(courseid);
//        courseSource.setTaskId();
            // 构建并保存资源信息到数据库
            courseSource.setFilesourcePath(filePath+newFilename);
            boolean insertSuccess = courseSourceMapper.insert(courseSource)>0;

            if (insertSuccess){
                //TODO:将文件存储在本地 改路径到配置文件
                File savedFile = convertMultipartFileToFile(file, "D:\\code\\代码\\java\\ilink\\src\\main\\resources\\data\\videOSource\\", newFilename);//+filePath


                // 将上传任务提交到线程池执行
                fileUploadTaskExecutor.execute(() -> processSourceUpload(savedFile, filePath, newFilename, courseSource));

                return R.ok("音视频文件已加入队列中处理，稍后处理: " + file.getOriginalFilename());
            }else {
                log.error("音视频文件加入mysql时失败: " + file.getOriginalFilename());
                return R.failure("音视频文件加入mysql时失败: " + file.getOriginalFilename());
            }
        }
        catch (Exception e) {
            log.error("音视频文件上传时出现异常: " + file.getOriginalFilename(), e);
            return R.failure("音视频文件上传时出现异常: " + file.getOriginalFilename(),e.getMessage());
        }

    }
    //处理音视频上传和加工
    private void processSourceUpload(File file, String filePath, String newFilename, CourseSource courseSource) {
        try {
            boolean uploadSuccess = ossService.uploadFile(file, filePath, newFilename);
            if (uploadSuccess) {
                courseSource.setOssWriteStatus(true);
                boolean updateSuccess =courseSourceMapper.updateById(courseSource)>0;
                if (!updateSuccess) {
                    log.error("课程:"+courseSource.getCourseId()+"中的音视频上传成功，但更新数据库失败: " + file.getName());
                    //需要进行回退处理删除
                    ossService.deleteFile(newFilename,filePath);
                    log.info("课程:"+courseSource.getCourseId()+"中的音视频上传成功，但更新数据库失败，已进行OSS删除回退处理: " + file.getName());
                }else {
                    log.info("课程:"+courseSource.getCourseId()+"中的音视频上传成功: " + file.getName());
                    String fileUrl = ossService.getFileUrl(courseSource.getFilesourcePath());
                    if(fileUrl == null){
                        log.error("课程:"+courseSource.getCourseId()+"中的音视频上传成功，但获取文件URL失败: " + file.getName());
                    }
                    //加工音视频，启用异步线程用于轮询加工状态直到加工完成，但这虽然默认使用线程池排队但这会导致线程闲置因此，需要对此优化
                    studyaboutTeacherService.checkVideoStatusAsync(courseSource.getCourseSourceId());
                    //将加工的任务提交到线程池执行，但前提是确保上传成功
                    videoHandleTaskExecutor.execute(() -> studyaboutTeacherService.handlefileTrans(courseSource,fileUrl));
                    log.info("课程:"+courseSource.getCourseId()+"中的音视频上传成功，已提交异步处理任务: " + file.getName());
                }

            } else {
                log.error("课程:"+courseSource.getCourseId()+"中的音视频上传失败: " + file.getName());

            }
        } catch (Exception e) {
            log.error("课程:"+courseSource.getCourseId()+"中的音视频上传中出现异常: " + file.getName(), e);
        }
    }


}